// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;


import org.apache.log4j.Logger;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;



public class EncryptionSecretKeyChecker  {

    private static final Logger s_logger = Logger.getLogger(EncryptionSecretKeyChecker.class);

    // Two possible locations with the new packaging naming
    private static final String s_altKeyFile = "e:\\pro\\key";
    private static final String s_keyFile = "e:\\pro\\key";
    private static final String s_envKey = "CLOUD_SECRET_KEY";
    private static StandardPBEStringEncryptor s_encryptor = new StandardPBEStringEncryptor();
    private static boolean s_useEncryption = false;

    public void check() {
        //Get encryption type from db.properties
        final File dbPropsFile = new File("e:\\pro\\db.properties");
        final Properties dbProps = new Properties();
        try {
            dbProps.load(new FileInputStream(dbPropsFile));

            final String encryptionType = dbProps.getProperty("db.cloud.encryption.type");

        

            if(encryptionType == null || encryptionType.equals("none")){
                return;
            }
            
            if (s_useEncryption) {
            	s_logger.warn("Encryption already enabled, is check() called twice?");
            	return;
            }

            s_encryptor.setAlgorithm("PBEWithMD5AndDES");
            String secretKey = null;

            SimpleStringPBEConfig stringConfig = new SimpleStringPBEConfig(); 

            if(encryptionType.equals("file")){
                File keyFile = new File(s_keyFile);
                if (!keyFile.exists()) {
                    keyFile = new File(s_altKeyFile);
                }
                try {
                    secretKey = new BufferedReader(new FileReader(keyFile)).readLine();
                    //Check for null or empty secret key
                } catch (FileNotFoundException e) {
                	System.out.printf("File containing secret key not found: "+s_keyFile, e);
                } catch (IOException e) {
                	System.out.printf("Error while reading secret key from: "+s_keyFile, e);
                }

                if(secretKey == null || secretKey.isEmpty()){
                	System.out.printf("Secret key is null or empty in file "+s_keyFile);
                }

            } else if(encryptionType.equals("env")){
                secretKey = System.getenv(s_envKey);
                if(secretKey == null || secretKey.isEmpty()){
                	System.out.printf("Environment variable "+s_envKey+" is not set or empty");
                }
            } else if(encryptionType.equals("web")){
                ServerSocket serverSocket = null;
                int port = 8097;
                try {
                    serverSocket = new ServerSocket(port);
                } catch (IOException ioex) {
                    System.out.printf("Error initializing secret key reciever", ioex);
                }
                Socket clientSocket = null;
                try {
                    clientSocket = serverSocket.accept();
                } catch (IOException e) {
                	System.out.printf("Accept failed on "+port);
                }
                PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
                BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                String inputLine;
                if ((inputLine = in.readLine()) != null) {
                    secretKey = inputLine;
                }
                out.close();
                in.close();
                clientSocket.close();
                serverSocket.close();
            } else {
            	System.out.printf("Invalid encryption type: "+encryptionType);
            }

            stringConfig.setPassword(secretKey);
            s_encryptor.setConfig(stringConfig);
            s_useEncryption = true;
        } catch (FileNotFoundException e) {
        	System.out.printf("File db.properties not found", e);
        } catch (IOException e) {
        	System.out.printf("Error while reading db.properties", e);
        }
    }

    public StandardPBEStringEncryptor getEncryptor() {
        return s_encryptor;
    }

    public static boolean useEncryption(){
        return s_useEncryption;
    }

    //Initialize encryptor for migration during secret key change
    public static void initEncryptorForMigration(String secretKey){
        s_encryptor.setAlgorithm("PBEWithMD5AndDES");
        SimpleStringPBEConfig stringConfig = new SimpleStringPBEConfig();
        stringConfig.setPassword(secretKey);
        s_encryptor.setConfig(stringConfig);
        s_useEncryption = true;
    }
    
    public boolean start() {
    	try {
    		check();
    	} catch (Exception e) {
			System.exit(1);
    	}
    	return true;
    }
}
